<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

	/**
	 * convert xml string to php array - useful to get a serializable value
	 *
	 * @param string $xmlstr
	 * @return array
	 * @author Adrien aka Gaarf
	 */
	class Payment_wxpay extends CI_Driver {
	
		protected $CI = '';
	
		protected $error = '';
		/**
		 *
		 * Zewei Fan（fans_wei@163.com）
		 * 2015-09-21 下午4:20:49
		 **/
		public function __construct()
		{
			$this->CI = & get_instance();
		}
		
		public $data;				//接收到的数据，类型为关联数组
		var $returnParameters;		//返回参数，类型为关联数组
		
		/*
			配置参数
		*/
		var $config = array(
			'appid' 		=> "wxd51316630a4a4ce4",    /*微信开放平台上的应用id*/
			'mch_id' 		=> "1404259502",   			/*微信申请成功之后邮件中的商户id*/
			'api_key' 		=> "27bcde12b201676bc71f590918879c23",    				/*在微信商户平台上自己设定的api密钥 32位*/
			'notify_url' 	=> '' 	/*自定义的回调程序地址id*/
		);
		
		
		//获取预支付订单
		public function getPrePayOrder( $param ){
			
			$url 		= "https://api.mch.weixin.qq.com/pay/unifiedorder";
			$notify_url = $this->config["notify_url"];
			$onoce_str 	= $this->getRandChar(32);

			$data["appid"] 				= $this->config["appid"];
			$data["body"] 				= $param['goods_name'];
			$data["mch_id"] 			= $this->config['mch_id'];
			$data["nonce_str"] 			= $onoce_str;
			$data["notify_url"] 		= $notify_url;
			$data["out_trade_no"] 		= $param['order_id'];
			$data["spbill_create_ip"] 	= $this->get_client_ip();
			$data["total_fee"] 			= $param['order_amount'];
			$data["trade_type"] 		= "APP";
			
			$sign = $this->getSign($data, false);
			$data["sign"] = $sign;

			$xml = $this->arrayToXml($data);
			$response = $this->postXmlCurl($xml, $url);

			Logs::pay('pay :: out_trade_no='.$param['order_id'].', '.$response);
			
			//将微信返回的结果xml转成数组
			return $this->xmlstr_to_array($response);
			
		}

		
		//执行第二次签名，才能返回给客户端使用
		public function getOrder($prepayId){

			$data["appid"] 		= $this->config["appid"];
			$data["noncestr"] 	= $this->getRandChar(32);;
			$data["package"] 	= "Sign=WXPay";
			$data["partnerid"] 	= $this->config['mch_id'];
			$data["prepayid"] 	= $prepayId;
			$data["timestamp"] 	= time();
			
			$sign = $this->getSign($data, false);
			$data["sign"] = $sign;

			return $data;
			
		}
		

		//生成签名
		function getSign($Obj){
			
			foreach ($Obj as $k => $v){
				$Parameters[strtolower($k)] = $v;
			}
			
			//签名步骤一：按字典序排序参数
			ksort($Parameters);
			
			$String = $this->formatBizQueryParaMap($Parameters, false);
			
			//echo "【string】 =".$String."</br>";
			//签名步骤二：在string后加入KEY
			$String = $String."&key=".$this->config['api_key'];
			
			Logs::pay($String);
			//echo "<textarea style='width: 50%; height: 150px;'>$String</textarea> <br />";
			
			//签名步骤三：MD5加密
			$result_ = strtoupper(md5($String));
			
			return $result_;
		}

		
		//获取指定长度的随机字符串
		function getRandChar($length){
			
			$str 	= null;
			$strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
			$max 	= strlen($strPol)-1;

			for($i=0; $i<$length; $i++){
				//rand($min,$max)生成介于min和max两个数之间的一个随机整数
				$str .= $strPol[rand(0,$max)];
			}

			return $str;
			
		}
		

		//数组转xml
		function arrayToXml($arr){
			
			$xml = "<xml>";
			
			foreach ($arr as $key=>$val){
				if (is_numeric($val)){
					$xml .= "<".$key.">".$val."</".$key.">"; 
				}else{
					$xml .= "<".$key."><![CDATA[".$val."]]></".$key.">";  
				}
			}
			
			$xml .= "</xml>";
			
			return $xml; 
		
		}

		
		//post https请求，CURLOPT_POSTFIELDS xml格式
		function postXmlCurl($xml,$url,$second=30){       
			//初始化curl        
			$ch = curl_init();
			
			//超时时间
			curl_setopt($ch,CURLOPT_TIMEOUT,$second);
			
			//这里设置代理，如果有的话
			//curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
			//curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
			curl_setopt($ch,CURLOPT_URL, $url);
			curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
			curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
			
			//设置header
			curl_setopt($ch, CURLOPT_HEADER, FALSE);
			
			//要求结果为字符串且输出到屏幕上
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
			
			//post提交方式
			curl_setopt($ch, CURLOPT_POST, TRUE);
			curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
			
			//运行curl
			$data = curl_exec($ch);
			
			//返回结果
			if($data){
				curl_close($ch);
				return $data;
			}else { 
				$error = curl_errno($ch);
				echo "curl出错，错误码:$error"."<br>";
				echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
				curl_close($ch);
				return false;
			}
			
		}

		
		//获取当前服务器的IP
		function get_client_ip(){
			
			if ($_SERVER['REMOTE_ADDR']) {
				$cip = $_SERVER['REMOTE_ADDR'];
			} elseif (getenv("REMOTE_ADDR")) {
				$cip = getenv("REMOTE_ADDR");
			} elseif (getenv("HTTP_CLIENT_IP")) {
				$cip = getenv("HTTP_CLIENT_IP");
			} else {
				$cip = "unknown";
			}
			
			return $cip;

		}
		

		//将数组转成uri字符串
		function formatBizQueryParaMap($paraMap, $urlencode){
			
			$buff = "";
			
			ksort($paraMap);
			
			foreach ($paraMap as $k => $v){
				if($urlencode){
					$v = urlencode($v);
				}
				$buff .= strtolower($k) . "=" . $v . "&";
			}
			
			$reqPar;
			
			if (strlen($buff) > 0){
				$reqPar = substr($buff, 0, strlen($buff)-1);
			}
			
			return $reqPar;
		}
		

		//xml转成数组
		function xmlstr_to_array($xmlstr) {
			
			$doc = new DOMDocument();
			$doc->loadXML($xmlstr);
			
			return $this->domnode_to_array($doc->documentElement);
		}
		
		
		//xml转成数组
		function domnode_to_array($node) {
			$output = array();
			switch ($node->nodeType) {
				case XML_CDATA_SECTION_NODE:
				
				case XML_TEXT_NODE:
					$output = trim($node->textContent);
					break;
				case XML_ELEMENT_NODE:
					for ($i=0, $m=$node->childNodes->length; $i<$m; $i++) {
						$child = $node->childNodes->item($i);
						$v = $this->domnode_to_array($child);
						if(isset($child->tagName)) {
							$t = $child->tagName;
							if(!isset($output[$t])) {
								$output[$t] = array();
							}
							$output[$t][] = $v;
						} elseif($v) {
							$output = (string) $v;
						}
					}
					if(is_array($output)) {
						if($node->attributes->length) {
							$a = array();
							foreach($node->attributes as $attrName => $attrNode) {
								$a[$attrName] = (string) $attrNode->value;
							}
							$output['@attributes'] = $a;
						}
						foreach ($output as $t => $v) {
							if(is_array($v) && count($v)==1 && $t!='@attributes') {
								$output[$t] = $v[0];
							}
						}
					}
					break;
			}
			return $output;
			
		}
		
		
		//验证签名
		public function checkSign(){
			
			$tmpData = $this->data;
			
			unset($tmpData['sign']);
			
			$sign = $this->getSign($tmpData);//本地签名
			
			if ($this->data['sign'] == $sign) {
				return TRUE;
			}
			return FALSE;
			
		}
		
		
		//将微信的请求xml转换成关联数组，以方便数据处理
		function saveData($xml){
			
			$this->data = $this->xmlToArray($xml);
			
		}
		
		
		//作用：将xml转为array
		public function xmlToArray($xml){		
			
			//将XML转为array        
			
			$array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);		
			
			return $array_data;
			
		}
		
		
		//设置返回微信的xml数据
		function setReturnParameter($parameter, $parameterValue){
			
			$this->returnParameters[$this->trimString($parameter)] = $this->trimString($parameterValue);
			
		}
		
		
		//是否存在
		function trimString($value){
			$ret = null;
			if (null != $value) {
				$ret = $value;
				if (strlen($ret) == 0) {
					$ret = null;
				}
			}
			return $ret;
		}
		
		
		//生成接口参数xml
		function createXml(){
			return $this->arrayToXml($this->returnParameters);
			
		}
		
		
		//将xml数据返回微信
		function returnXml(){

			$returnXml = $this->createXml();
			
			Logs::pay('notify :: out_trade_no='.$this->data['out_trade_no'].', '.$returnXml);

			return $returnXml;
		
		}
		
	}

	
	
	/*
		header("Content-type: text/html; charset=utf-8");
	
		public function pay(){
		
			$this->load->library('/Payment/WxPayHelper');
			
			$orderBody 	= "test商品";
			$tade_no 	= "abc_" . time();
			$total_fee 	= 1;
			$WxPayHelper = new WxPayHelper();
			$response 	= $WxPayHelper->getPrePayOrder($orderBody, $tade_no, $total_fee);
			
			if($response['return_code'] == 'SUCCESS'){
				$x = $WxPayHelper->getOrder($response['prepay_id']);
				print_R($x);
			}else{
				print_R($response);
			}
			
		}
		
		
		public function notify(){
		
			//存储微信的回调
			$xml = isset($GLOBALS["HTTP_RAW_POST_DATA"]) ? $GLOBALS["HTTP_RAW_POST_DATA"] : "<xml>
	  <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
	  <attach><![CDATA[支付测试]]></attach>
	  <bank_type><![CDATA[CFT]]></bank_type>
	  <fee_type><![CDATA[CNY]]></fee_type>
	  <is_subscribe><![CDATA[Y]]></is_subscribe>
	  <mch_id><![CDATA[10000100]]></mch_id>
	  <nonce_str><![CDATA[5d2b6c2a8db53831f7eda20af46e531c]]></nonce_str>
	  <openid><![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]]></openid>
	  <out_trade_no><![CDATA[14098116531]]></out_trade_no>
	  <result_code><![CDATA[SUCCESS]]></result_code>
	  <return_code><![CDATA[SUCCESS]]></return_code>
	  <sign><![CDATA[3583894911429EBE6BAEFC4308A2FF56]]></sign>
	  <sub_mch_id><![CDATA[10000100]]></sub_mch_id>
	  <time_end><![CDATA[20140903131540]]></time_end>
	  <total_fee>1</total_fee>
	  <trade_type><![CDATA[JSAPI]]></trade_type>
	  <transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id>
	</xml>";
			
			$this->load->library('/Payment/WxPayHelper');
			$WxPayHelper = new WxPayHelper();
				
			if($xml){
				
				$WxPayHelper->saveData($xml);

				if($WxPayHelper->checkSign() == FALSE){
					
					$WxPayHelper->setReturnParameter("return_code", "FAIL");//返回状态码
					$WxPayHelper->setReturnParameter("return_msg", "签名失败");//返回信息
				
				}else{
					
					$WxPayHelper->setReturnParameter("return_code", "SUCCESS");//设置返回码
					
					//同步订单状态
					
				
				}
				
			}else{
			
				$WxPayHelper->setReturnParameter("return_code", "FAIL");//返回状态码
				$WxPayHelper->setReturnParameter("return_msg", "返回数据为空");//返回信息
			
			}
			
			
			$returnXml = $WxPayHelper->returnXml();
			
			echo $returnXml;
			
		}
		
	*/